<template>
    <tnxel-submit-form ref="form" class="layer-form" :model="model" :rules="rules" label-width="126">
        <el-form-item class="mb-3" label="包含层级" prop="layers">
            <el-checkbox-group v-model="model.layers" @change="onLayersChange">
                <ul class="ps-0">
                    <li class="d-flex" v-for="layer of moduleLayerValues" :key="layer.name">
                        <el-checkbox :value="layer.name"
                            :disabled="(ModuleLayer.API.equals(layer) || ModuleLayer.REPO.equals(layer)) && !model.layers.includes(ModuleLayer.MODEL.name)">
                            <el-tag type="info" :title="layer.caption + '层'">{{ layer.name.toLowerCase() }}</el-tag>
                        </el-checkbox>
                        <div class="form-item-tip ms-2"
                            v-if="ModuleLayer.API.equals(layer) && !model.layers.includes(ModuleLayer.MODEL.name)">
                            标准模块中必须包含model（模型层）才可包含api（接口层）
                        </div>
                        <template v-if="ModuleLayer.REPO.equals(layer)">
                            <div class="form-item-tip ms-2" v-if="!model.layers.includes(ModuleLayer.MODEL.name)">
                                标准模块中必须包含model（模型层）才可包含repo（数据访问层）
                            </div>
                            <template v-if="model.layers.includes(ModuleLayer.REPO.name)">
                                <tnxel-icon class="m-2 text-placeholder" value="Minus" :size="14"/>
                                <div class="repo-types">
                                    <tnxel-enum-select v-model="model.repoTypes" type="RepoType"
                                        selector="checkbox"/>
                                </div>
                                <div class="form-item-tip mt-1">数据库使用默认配置，请在生成的配置文件中根据实际情况更改
                                </div>
                            </template>
                        </template>
                        <div v-if="ModuleLayer.WEB.equals(layer) && model.layers.includes(ModuleLayer.WEB.name)">
                            <div class="flex-v-center">
                                <tnxel-icon class="m-2 text-placeholder" value="Minus" :size="14"/>
                                <div class="flex-v-center">
                                    <el-checkbox-group v-model="model.ssrEnabled" :disabled="model.ssrEnabledDisabled">
                                        <el-checkbox value="SSR">支持服务端渲染</el-checkbox>
                                    </el-checkbox-group>
                                    <span class="form-item-tip" v-if="model.ssrEnabledDisabled">
                                        已在依赖的模块中启用
                                    </span>
                                </div>
                            </div>
                            <div class="flex-v-center" v-if="!parent.singleArch">
                                <tnxel-icon class="m-2 text-placeholder" value="Minus" :size="14"/>
                                <div class="flex-v-center">
                                    <el-checkbox-group v-model="model.nacosEnabled"
                                        :disabled="model.nacosEnabledDisabled">
                                        <el-checkbox :value="true">使用Nacos</el-checkbox>
                                    </el-checkbox-group>
                                    <span class="form-item-tip" v-if="model.nacosEnabledDisabled">
                                        已在依赖的模块中启用
                                    </span>
                                </div>
                            </div>
                        </div>
                    </li>
                </ul>
            </el-checkbox-group>
        </el-form-item>
        <el-form-item label="子模块groupId" prop="layerGroupId">
            <el-input v-model="model.layerGroupId" placeholder="请输入"/>
            <div class="form-item-tip">所有层级子模块采用一致的groupId</div>
        </el-form-item>
    </tnxel-submit-form>
</template>

<script>
import tnx from '@/tnx.js';
import ModuleLayer from '@/logic/maven/enums/ModuleLayer.js';
import RepoType from '@/logic/maven/enums/RepoType.js';
import ProjectUtil from '@/logic/maven/util/project.js';

const getModuleLayerValues = function (singleArch) {
    return ModuleLayer.values(singleArch ? 'single' : 'microservice');
}

export default {
    components: {},
    props: {
        root: {
            type: Object,
            required: true,
        },
        parent: {
            type: Object,
            required: true,
        },
        dependencyModules: Array,
        after: Function,
    },
    data() {
        let model = {
            layers: [],
            repoTypes: [],
            ssrEnabled: [],
            ssrEnabledDisabled: false,
            nacosEnabled: [],
            nacosEnabledDisabled: false,
            layerGroupId: this.parent.layerGroupId,
        };
        if (this.parent.modules) {
            for (let module of this.parent.modules) {
                let layer = ProjectUtil.getLayerKey(module.artifactId).toUpperCase();
                if (this.isValidLayer(layer)) {
                    model.layers.push(layer);
                    model.layerGroupId = module.groupId;
                    let dependencies = module.dependencies || [];
                    if (layer === ModuleLayer.REPO.name) {
                        model.repoTypes = ProjectUtil.getRepoTypes(dependencies);
                    } else if (layer === ModuleLayer.WEB.name) {
                        let ssrEnabled = ProjectUtil.getSsrEnabled(this.root, module);
                        if (ssrEnabled) {
                            model.ssrEnabled.push('SSR');
                            model.ssrEnabledDisabled = ssrEnabled === 'indirect'; // 间接启用则禁用
                        }
                        let nacosEnabled = ProjectUtil.getNacosEnabled(this.root, module);
                        if (nacosEnabled) {
                            model.nacosEnabled.push(true);
                            model.nacosEnabledDisabled = nacosEnabled === 'indirect'; // 间接启用则禁用
                        }
                    }
                }
            }
        }
        if (!model.layers.length) { // 默认选择所有层级
            model.layers = getModuleLayerValues(this.parent.singleArch).map(layer => layer.name);
        }
        if (!model.repoTypes.length) {
            model.repoTypes.push(RepoType.JPA.name);
        }
        if (!model.layerGroupId) {
            model.layerGroupId = ProjectUtil.getDefaultGroupId(this.parent);
        }
        return {
            model: model,
            ModuleLayer: ModuleLayer,
            rules: {
                layers: [tnx.app.validator.requiredRule],
                layerGroupId: [tnx.app.validator.requiredRule],
            },
        };
    },
    computed: {
        moduleLayerValues() {
            return getModuleLayerValues(this.parent.singleArch);
        },
    },
    methods: {
        dialog() {
            return {
                width: 560,
                type: 'confirm',
                click: this.toSubmit,
            }
        },
        toSubmit(yes, callback) {
            if (yes) {
                this.$refs.form.toSubmit(() => {
                    let modules = this.getModules();
                    let after = this.after || callback;
                    if (after) {
                        after(modules);
                    }
                });
            }
        },
        getModules() {
            let modules = [];

            let layers = this.model.layers || [];
            layers.sort();
            let artifactIdPrefix = this.getArtifactIdPrefix();
            for (let layer of layers) {
                if (this.isValidLayer(layer)) {
                    let artifactId = artifactIdPrefix + '-' + layer.toLowerCase();
                    let module = {
                        groupId: this.model.layerGroupId,
                        artifactId: artifactId,
                        parent: {
                            groupId: this.parent.groupId,
                            artifactId: this.parent.artifactId,
                        },
                        dependencies: this.getLayerDependencies(layer),
                    };
                    if (layer === ModuleLayer.WEB.name) {
                        module.packaging = 'war';
                    }
                    modules.push(module);
                }
            }

            return modules;
        },
        getArtifactIdPrefix() {
            let artifactIdPrefix = this.parent.artifactId;
            // 规则：子模块groupId的结尾段（按.分割）与父artifactId的结尾段（按-分割）不一致时，
            // 将子模块artifactId前缀去掉父artifactId的结尾段
            let layerGroupSuffix = (this.model.layerGroupId || '').split('.').pop();
            let parentArtifactSuffix = (this.parent.artifactId || '').split('-').pop();
            if (layerGroupSuffix !== parentArtifactSuffix) {
                parentArtifactSuffix = '-' + parentArtifactSuffix;
                if (artifactIdPrefix.endsWith(parentArtifactSuffix)) {
                    artifactIdPrefix =
                        artifactIdPrefix.substring(0, artifactIdPrefix.length - parentArtifactSuffix.length);
                }
            }
            return artifactIdPrefix;
        },
        onLayersChange() {
            this.$refs.form.validate(() => {
                if (!this.model.layers.includes(ModuleLayer.MODEL.name)) {
                    this.model.layers.remove(ModuleLayer.API.name);
                    this.model.layers.remove(ModuleLayer.REPO.name);
                }
            });
        },
        validate() {
            this.$refs.form.validate(...arguments);
        },
        isValidLayer(layer) {
            return layer && ModuleLayer.valueOf(layer.toUpperCase());
        },
        pushDependencyModuleLayerDependency(dependencies, layer) {
            let result = false;
            if (this.dependencyModules?.length) {
                for (let dependencyModule of this.dependencyModules) {
                    if (dependencyModule.modules?.length) {
                        for (let dependencySubModule of dependencyModule.modules) {
                            if (dependencySubModule.artifactId.endsWith('-' + layer.toLowerCase())) {
                                dependencies.push({
                                    groupId: dependencySubModule.groupId,
                                    artifactId: dependencySubModule.artifactId,
                                    version: '${project.version}',
                                });
                                result = true;
                            }
                        }
                    }
                }
            }
            return result;
        },
        getLayerDependencies(layer) {
            let dependencies = [];
            if (this.model.layers.includes(layer)) {
                switch (layer) {
                    case ModuleLayer.API.name: {
                        // api层不依赖于依赖模块的api层
                        dependencies.push({
                            groupId: 'org.springframework.cloud',
                            artifactId: 'spring-cloud-openfeign-core',
                        }, {
                            groupId: this.model.layerGroupId,
                            artifactId: this.getArtifactIdPrefix() + '-model',
                            version: '${project.version}',
                        });
                        break;
                    }
                    case ModuleLayer.MODEL.name: {
                        if (!this.pushDependencyModuleLayerDependency(dependencies, layer)) {
                            dependencies.push({
                                groupId: 'org.truenewx.tnxjee',
                                artifactId: 'tnxjee-model',
                            });
                        }
                        break;
                    }
                    case ModuleLayer.REPO.name: {
                        if (!this.pushDependencyModuleLayerDependency(dependencies, layer)) {
                            dependencies.push({
                                groupId: 'org.flywaydb',
                                artifactId: 'flyway-mysql',
                            }, {
                                groupId: 'com.mysql',
                                artifactId: 'mysql-connector-j',
                            });
                        }
                        for (let repoType of this.model.repoTypes) {
                            dependencies.push({
                                groupId: 'org.truenewx.tnxjee',
                                artifactId: 'tnxjee-repo-' + repoType.toLowerCase(),
                            });
                        }
                        dependencies.push({
                            groupId: this.model.layerGroupId,
                            artifactId: this.getArtifactIdPrefix() + '-model',
                            version: '${project.version}',
                        });
                        break;
                    }
                    case ModuleLayer.SERVICE.name: {
                        if (!this.pushDependencyModuleLayerDependency(dependencies, layer)) {
                            dependencies.push({
                                groupId: 'org.truenewx.tnxjee',
                                artifactId: 'tnxjee-service-impl',
                            });
                        }
                        if (this.model.layers.includes(ModuleLayer.REPO.name)) {
                            dependencies.push({
                                groupId: this.model.layerGroupId,
                                artifactId: this.getArtifactIdPrefix() + '-repo',
                                version: '${project.version}',
                            });
                        } else if (this.model.layers.includes(ModuleLayer.MODEL.name)) {
                            dependencies.push({
                                groupId: this.model.layerGroupId,
                                artifactId: this.getArtifactIdPrefix() + '-model',
                                version: '${project.version}',
                            });
                        }
                        dependencies.push({
                            groupId: 'org.truenewx.tnxjee',
                            artifactId: 'tnxjee-test-service',
                            scope: 'test',
                        }, {
                            groupId: 'com.h2database',
                            artifactId: 'h2',
                            scope: 'test',
                        }, {
                            groupId: 'org.apache.tomcat.embed',
                            artifactId: 'tomcat-embed-el',
                            scope: 'test',
                        });
                        break;
                    }
                    case ModuleLayer.WEB.name: {
                        if (!this.pushDependencyModuleLayerDependency(dependencies, layer)) {
                            dependencies.push({
                                groupId: 'org.springframework.boot',
                                artifactId: 'spring-boot-starter-web',
                            });
                            if (this.model.nacosEnabled.includes(true)) {
                                dependencies.push({
                                    groupId: 'com.alibaba.cloud',
                                    artifactId: 'spring-cloud-starter-alibaba-nacos-config',
                                });
                            }
                        }
                        if (this.model.ssrEnabled.includes('SSR')) {
                            dependencies.push({
                                groupId: 'org.truenewx.tnxjee',
                                artifactId: 'tnxjee-webmvc-view',
                            });
                        } else {
                            dependencies.push({
                                groupId: 'org.truenewx.tnxjee',
                                artifactId: 'tnxjee-webmvc',
                            });
                        }
                        if (this.model.layers.includes(ModuleLayer.API.name)) {
                            dependencies.push({
                                groupId: this.model.layerGroupId,
                                artifactId: this.getArtifactIdPrefix() + '-api',
                                version: '${project.version}',
                            });
                        }
                        if (this.model.layers.includes(ModuleLayer.SERVICE.name)) {
                            dependencies.push({
                                groupId: this.model.layerGroupId,
                                artifactId: this.getArtifactIdPrefix() + '-service',
                                version: '${project.version}',
                            });
                        } else if (this.model.layers.includes(ModuleLayer.MODEL.name)) {
                            dependencies.push({
                                groupId: this.model.layerGroupId,
                                artifactId: this.getArtifactIdPrefix() + '-model',
                                version: '${project.version}',
                            });
                        }
                        break;
                    }
                }
            }
            return dependencies;
        },
    }
}
</script>

<style lang="scss" scoped>
.el-form-item__content {
    .layer-form {
        :deep(.el-form-item__label) {
            font-weight: 400;
        }
    }
}

.layer-form {
    width: 100%;

    .repo-types {
        .el-checkbox-group {
            flex-direction: column;
            align-items: start;
        }
    }

}
</style>
